<?php

namespace Nhan\Realtime;

use Evenement\EventEmitterInterface;
use Exception;
use Ratchet\ConnectionInterface;
use SplObjectStorage;
use Nhan\Realtime\AppModels\ChatModel;

class RealtimeApp implements MessengerInterface {

    protected $clients;
    protected $emitter;
    protected $id = 1;

    public function getClientByConnection(ConnectionInterface $conn) {
        foreach ($this->clients as $client) {
            if ($client->getConnection() === $conn) {
                return $client;
            }
        }
        return null;
    }

    public function getClientByResourceId($resourceId) {
        foreach ($this->clients as $client) {
            $this->emitter->emit("debug", [$client, "Client has Ri: " . $client->getResourceId() . " var Ri= " . $resourceId]);
            if ($client->getResourceId() == $resourceId) {
                $this->emitter->emit("debug", [$client, "Client has Ri: " . $client->getResourceId() . " exist"]);
                return $client;
            }
        }
        return null;
    }

    public function getEmitter() {
        return $this->emitter;
    }

    public function setEmitter(EventEmitterInterface $emitter) {
        $this->emitter = $emitter;
    }

    public function getClients() {
        return $this->clients;
    }

    public function __construct(EventEmitterInterface $emitter) {
        $this->emitter = $emitter;
        $this->clients = new SplObjectStorage();
    }

    public function onOpen(ConnectionInterface $con) {
        $client = new ClientConnection();
        $client->setId($this->id++);
        $client->setConnection($con);
        $this->clients->attach($client);
        $this->emitter->emit("debug", [$client, "Recent connectd: " . $client->getResourceId()]);
        $client->getConnection()->send($client->getResourceId());
    }
    
    public function onMessage(ConnectionInterface $con, $param) {
        $client = $this->getClientByConnection($con);

        //convert request param from client to object
        $param = json_decode($param);

        //from connection id
        $fromId = $param->fromId;

        //to connection id
        $toId = $param->toId;

        //data retrive from request
        $requestData = $param->data;

        //store all clients who will receive the message
        $targetClients = new SplObjectStorage();

        //response data
        $response = new ResponseData("", "");

        switch ($param->type) {
            case "chat": {
                    //get the target client

                    $targetClient = $this->getClientByResourceId($toId);
                    if ($targetClient != null) {
                        $targetClients->attach($targetClient);
                    }

                    //get response data
                    $message = $requestData->message;
                    $chatResult = new ChatModel($fromId, $toId, $message); //__construct($fromId, $toId, $message)
                    
                    $response->setData(json_encode($chatResult));
                    $response->setType("chat");
                    $this->emitter->emit("debug", [$client, $param]);
                    break;
                }
            case "message": {
                    $response->setData("this is data from message type");
                    $response->setType("message");

                    $this->emitter->emit("debug", [$client, $param]);
                    break;
                }
            case "comment": {
                    $response->setData("this is data from comment type");
                    $response->setType("comment");

                    $this->emitter->emit("debug", [$client, $response]);
                    break;
                }
            case "like": {
                    $response->setData("this is data from like type");
                    $response->setType("like");

                    $this->emitter->emit("debug", [$client, $result]);
                    break;
                }

            case "addFriend": {
                    $response->setData("this is data from addFriend type");
                    $response->setType("addFriend");

                    $this->emitter->emit("debug", [$client, $result]);
                    break;
                }
        }
        
        //send data back to client
        foreach ($targetClients as $client) {
            $client->getConnection()->send(json_encode($response));
        }
    }

    public function onClose(ConnectionInterface $con) {
        $client = $this->getClientByConnection($con);

        if ($client) {
            $this->clients->detach($client);
            $this->emitter->emit("close", [$client]);
        }
    }

    public function onError(ConnectionInterface $con, Exception $exception) {
        $client = $this->getClientByConnection($con);

        if ($client) {
            $client->getConnection()->close();
            $this->emitter->emit("error", [$client, $exception]);
        }
    }

}
